import { REALM_BIG_LEVEL_TYPE, type RealmBigLevelType } from '../../data/realm';
import { RealmReader } from '../realm/realm-reader';
import { ATTRIBUTE_TYPE, type Attribute, type AttributeType } from './type';

export interface LogGrowthCfg {
  /** 一级基础值 */
  base: number;
  /** 每级增加值(对数幅度) */
  grow: number;
  /** 后期减速指数 */
  fade: number;
}

/**
 * 属性来源类型枚举
 * 定义属性加成的不同来源渠道
 */
export const ATTRIBUTE_SOURCE = {
  /** 装备提供的属性加成 */
  EQUIPMENT: 'EQUIPMENT',
} as const;

/** 属性来源类型的类型定义 */
export type AttributeSource =
  (typeof ATTRIBUTE_SOURCE)[keyof typeof ATTRIBUTE_SOURCE];

/**
 * 属性修改器优先级常量
 * 数值越小越先应用，建议范围 0-100
 */
export const ATTRIBUTE_PRIORITY = {
  /** 系统级强制规则（属性上限、强制修正等） */
  SYSTEM: 0,
  /** 基础属性修正（职业修正、天赋修正等） */
  BASE_CORRECTION: 10,
  /** 装备套装效果 */
  EQUIPMENT_SET: 20,
  /** 单件装备效果 */
  EQUIPMENT: 30,
  /** 固定数值的增益效果 */
  BUFF_FIXED: 40,
  /** 百分比增益效果 */
  BUFF_PERCENT: 50,
  /** 固定数值的减益效果 */
  DEBUFF_FIXED: 60,
  /** 百分比减益效果 */
  DEBUFF_PERCENT: 70,
  /** 临时效果、环境效果 */
  TEMPORARY: 80,
  /** 属性上限限制（确保最后应用） */
  CAP_LIMIT: 90,
} as const;

/** 属性修改器优先级类型定义 */
export type AttributePriority =
  (typeof ATTRIBUTE_PRIORITY)[keyof typeof ATTRIBUTE_PRIORITY];

/**
 * 属性修改项接口
 * 描述对角色属性的具体修改方式
 */
export interface AttributeModifier {
  /** 属性来源类型 */
  source: AttributeSource;
  /** 来源的唯一标识（如装备 ID、技能 ID 等） */
  key: string;
  /** 属性加成值（加算） */
  attributes: Partial<Attribute>;
  /** 属性加成系数（乘算），可选 */
  multiplier?: Partial<Attribute>;
  /**
   * 应用优先级，数值越小越先应用
   * @default 0
   */
  priority?: AttributePriority;
}

export const DEFAULT_INITIAL_BASE_ATTRIBUTES = {
  [ATTRIBUTE_TYPE.HEALTH]: 100,
  [ATTRIBUTE_TYPE.ATTACK]: 20,
  [ATTRIBUTE_TYPE.DEFENSE]: 15,
  [ATTRIBUTE_TYPE.SPEED]: 1,
};

export const PRESET_SNAPPY = {
  /** 爽快前期：前期爆发高，后期放缓 */
  log: {
    [ATTRIBUTE_TYPE.HEALTH]: { base: 120, grow: 45, fade: 0.6 },
    [ATTRIBUTE_TYPE.ATTACK]: { base: 25, grow: 18, fade: 0.65 },
    [ATTRIBUTE_TYPE.DEFENSE]: { base: 18, grow: 12, fade: 0.7 },
    [ATTRIBUTE_TYPE.SPEED]: { base: 1.2, grow: 0.25, fade: 0.75 },
  } as Partial<Record<AttributeType, LogGrowthCfg>>,
  lin: {
    [ATTRIBUTE_TYPE.HEALTH]: 6,
    [ATTRIBUTE_TYPE.ATTACK]: 1.5,
    [ATTRIBUTE_TYPE.DEFENSE]: 1.2,
    [ATTRIBUTE_TYPE.SPEED]: 0.08,
  } as Partial<Attribute>,
};

export const PRESET_HARD = {
  /** 硬核后期：前期克制，后期依旧明显成长 */
  log: {
    [ATTRIBUTE_TYPE.HEALTH]: { base: 100, grow: 60, fade: 0.85 },
    [ATTRIBUTE_TYPE.ATTACK]: { base: 20, grow: 25, fade: 0.9 },
    [ATTRIBUTE_TYPE.DEFENSE]: { base: 15, grow: 20, fade: 0.9 },
    [ATTRIBUTE_TYPE.SPEED]: { base: 1.0, grow: 0.35, fade: 0.8 },
  } as Partial<Record<AttributeType, LogGrowthCfg>>,
  lin: {
    [ATTRIBUTE_TYPE.HEALTH]: 3,
    [ATTRIBUTE_TYPE.ATTACK]: 0.8,
    [ATTRIBUTE_TYPE.DEFENSE]: 0.6,
    [ATTRIBUTE_TYPE.SPEED]: 0.05,
  } as Partial<Attribute>,
};

export type GrowthPreset = typeof PRESET_SNAPPY | typeof PRESET_HARD;

/**
 * 角色属性管理类
 * 负责管理角色的基础属性、等级成长和各种属性加成
 */
export class CharacterAttributes {
  /** 1 级时的初始基础属性 */
  private initialBaseAttributes: Attribute;
  /** 当前等级下的基础属性（包含等级成长） */
  private currentBaseAttributes: Attribute;
  /** 当前生效的所有属性修改器 */
  private modifiers: AttributeModifier[] = [];
  /** 当前战斗等级 */
  private level: number = 1;
  /** 各属性的等级成长系数配置 */
  private growthFactors: Partial<Attribute> = PRESET_SNAPPY.lin;
  private logGrowthCfg: Partial<Record<AttributeType, LogGrowthCfg>> =
    PRESET_SNAPPY.log;
  private realmType: RealmBigLevelType = REALM_BIG_LEVEL_TYPE.FAN_REN;
  private realmSmall: number = 1;
  private smallMulPerLayer: number = 0.05; // 5 %
  private realmMultiplier: number = 2.0; // 每差 1 个大境界 ×2
  /** 是否处于 "固定属性" 模式 */
  private isFixedMode: boolean = false;

  /**
   * 构造函数
   * @param initialBaseAttributes 1 级时的初始基础属性
   */
  constructor(initialBaseAttributes: Attribute) {
    this.initialBaseAttributes = { ...initialBaseAttributes };
    this.currentBaseAttributes = { ...initialBaseAttributes };
    this.validateAttributes(this.currentBaseAttributes);
    this.recalculateBaseAttributes();
  }

  /** 重新配置 */
  public resetInitialBaseAttributes(initialBaseAttributes: Attribute) {
    this.initialBaseAttributes = { ...initialBaseAttributes };
    this.currentBaseAttributes = { ...initialBaseAttributes };
    this.validateAttributes(this.currentBaseAttributes);
    this.recalculateBaseAttributes();
  }

  /**
   * 热切换成长预设（SNAPPY / HARD）
   */
  public applyPreset(preset: GrowthPreset): void {
    this.logGrowthCfg = preset.log;
    this.growthFactors = preset.lin;
    this.recalculateBaseAttributes();
  }

  markFixedMode(): void {
    this.isFixedMode = true;
    this.growthFactors = { HEALTH: 0, ATTACK: 0, DEFENSE: 0, SPEED: 0 };
    const zeroCfg: LogGrowthCfg = { base: 0, grow: 0, fade: 1 };
    (Object.keys(ATTRIBUTE_TYPE) as AttributeType[]).forEach(
      (k) => (this.logGrowthCfg[k] = zeroCfg)
    );

    this.realmMultiplier = 1.0;
    this.smallMulPerLayer = 0;

    this.recalculateBaseAttributes();
  }

  public setRealm(bigLevelType: RealmBigLevelType, smallLevel = 1): void {
    this.realmType = bigLevelType;
    this.realmSmall = Math.max(1, smallLevel);
    this.recalculateBaseAttributes();
  }

  /**
   * 设置角色等级并重新计算基础属性
   * @param level 新的等级
   * @throws 当等级不合法时抛出错误
   */
  public setLevel(level: number): void {
    if (level < 1) throw new Error('等级不能小于1');
    if (!Number.isInteger(level)) throw new Error('等级必须是整数');

    this.level = level;
    this.recalculateBaseAttributes();
  }

  /**
   * 获取当前角色等级
   * @returns 当前等级
   */
  public getLevel(): number {
    return this.level;
  }

  /**
   * 添加属性修改器
   * @param modifier 要添加的属性修改器
   * @throws 当属性值或乘算系数无效时抛出错误
   */
  public addModifier(modifier: AttributeModifier): void {
    this.validateAttributes(modifier.attributes);
    if (modifier.multiplier) {
      Object.values(modifier.multiplier).forEach((value) => {
        if (value < 0) throw new Error('乘算系数不能为负数');
      });
    }

    // 移除同来源同标识的旧修改器，避免重复
    this.removeModifier(modifier.source, modifier.key);
    this.modifiers.push(modifier);
    // 按优先级排序，数值小的优先
    this.modifiers.sort((a, b) => (a.priority || 0) - (b.priority || 0));
  }

  /**
   * 移除特定的属性修改器
   * @param source 修改器来源
   * @param key 修改器标识
   * @returns 是否成功移除了修改器
   */
  public removeModifier(source: AttributeSource, key: string): boolean {
    const initialLength = this.modifiers.length;
    this.modifiers = this.modifiers.filter(
      (mod) => !(mod.source === source && mod.key === key)
    );
    return this.modifiers.length !== initialLength;
  }

  /**
   * 移除指定来源的所有属性修改器
   * @param source 要移除的修改器来源
   * @returns 移除的修改器数量
   */
  public removeModifiersBySource(source: AttributeSource): number {
    const initialLength = this.modifiers.length;
    this.modifiers = this.modifiers.filter((mod) => mod.source !== source);
    return initialLength - this.modifiers.length;
  }

  /**
   * 获取所有属性修改器的只读副本
   * @returns 属性修改器数组的只读视图
   */
  public getModifiers(): ReadonlyArray<AttributeModifier> {
    return [...this.modifiers];
  }

  /**
   * 计算最终属性值（基础属性 + 所有加成）
   * @returns 包含最终属性值的对象
   */
  public calculateFinalAttributes(): Attribute {
    // 初始化最终属性（复制基础属性）
    const final: Attribute = { ...this.currentBaseAttributes };

    // 收集所有加算属性
    const additiveBonus: Partial<Attribute> = {};

    // 收集所有乘算属性（按优先级分组）
    const multipliers: Array<Partial<Attribute>> = [];

    // 处理所有修改器，分离加算和乘算
    this.modifiers.forEach((modifier) => {
      // 累加加算属性
      Object.keys(modifier.attributes).forEach((key) => {
        const attributeKey = key as AttributeType;
        additiveBonus[attributeKey] =
          (additiveBonus[attributeKey] || 0) +
          (modifier.attributes[attributeKey] || 0);
      });

      // 收集乘算属性
      if (modifier.multiplier) {
        multipliers.push(modifier.multiplier);
      }
    });

    // 应用加算属性
    Object.keys(additiveBonus).forEach((key) => {
      const attributeKey = key as AttributeType;
      final[attributeKey] += additiveBonus[attributeKey] || 0;
    });

    // 按顺序应用乘算属性
    multipliers.forEach((multiplier) => {
      Object.keys(multiplier).forEach((key) => {
        const attributeKey = key as AttributeType;
        const multiplierValue = multiplier[attributeKey] || 1;
        final[attributeKey] = final[attributeKey] * multiplierValue;
      });
    });

    // 确保属性值不为负数且是有效数字
    Object.keys(final).forEach((key) => {
      const attributeKey = key as AttributeType;
      if (!Number.isFinite(final[attributeKey])) {
        final[attributeKey] = 0;
      } else {
        final[attributeKey] = Math.max(0, final[attributeKey]);
      }
    });

    return final;
  }

  /**
   * 获取当前基础属性（包含等级成长，不含外部加成）
   * @returns 基础属性的只读副本
   */
  public getBaseAttributes(): Readonly<Attribute> {
    return { ...this.currentBaseAttributes };
  }

  /**
   * 获取初始基础属性（1级时的原始属性）
   * @returns 初始属性的只读副本
   */
  public getInitialBaseAttributes(): Readonly<Attribute> {
    return { ...this.initialBaseAttributes };
  }

  /**
   * 更新基础属性（用于角色重设或其他特殊情况）
   * @param newAttributes 新的基础属性值
   */
  public updateBaseAttributes(newAttributes: Partial<Attribute>): void {
    this.validateAttributes(newAttributes);
    this.initialBaseAttributes = {
      ...this.initialBaseAttributes,
      ...newAttributes,
    };
    this.recalculateBaseAttributes();
  }

  /**
   * 设置属性成长系数
   * @param factors 新的成长系数配置
   */
  public setGrowthFactors(factors: Partial<Attribute>): void {
    this.validateAttributes(factors);
    this.growthFactors = { ...this.growthFactors, ...factors };
    this.recalculateBaseAttributes();
  }

  /**
   * 获取当前成长系数配置
   * @returns 成长系数的只读副本
   */
  public getGrowthFactors(): Readonly<Partial<Attribute>> {
    return { ...this.growthFactors };
  }

  public setLogGrowthCfg(
    cfg: Partial<Record<AttributeType, LogGrowthCfg>>
  ): void {
    this.logGrowthCfg = { ...this.logGrowthCfg, ...cfg };
    this.recalculateBaseAttributes();
  }

  public getLogGrowthCfg(): Readonly<
    Partial<Record<AttributeType, LogGrowthCfg>>
  > {
    return { ...this.logGrowthCfg };
  }

  /**
   * 获取指定属性的最终值
   * @param key 属性键
   * @returns 该属性的最终数值
   */
  public getAttributeValue(key: AttributeType): number {
    const finalAttributes = this.calculateFinalAttributes();
    return finalAttributes[key];
  }

  /**
   * 获取属性快照（用于调试或 UI 显示）
   * @returns 包含所有属性相关信息的快照对象
   */
  public getAttributeSnapshot(): {
    /** 初始属性（1 级时） */
    initial: Readonly<Attribute>;
    /** 当前基础属性（含等级成长） */
    base: Readonly<Attribute>;
    /** 最终属性（含所有加成） */
    final: Attribute;
    /** 当前生效的所有修改器 */
    modifiers: ReadonlyArray<AttributeModifier>;
    /** 当前等级 */
    level: number;
  } {
    return {
      initial: this.getInitialBaseAttributes(),
      base: this.getBaseAttributes(),
      final: this.calculateFinalAttributes(),
      modifiers: this.getModifiers(),
      level: this.level,
    };
  }

  /**
   * 重新计算基础属性（基于当前等级和成长系数）
   */
  private recalculateBaseAttributes(): void {
    const base: Attribute = { ...this.initialBaseAttributes };

    /* 战斗等级成长（同境界内） */
    for (const k of Object.keys(base) as AttributeType[]) {
      const cfg = this.logGrowthCfg[k];
      const lin = this.growthFactors[k] || 0;
      const logPart = this.isFixedMode
        ? 0
        : cfg
        ? this.attrAtLevel(this.level, cfg.base, cfg.grow, cfg.fade) - cfg.base
        : 0;
      const linPart = this.isFixedMode ? 0 : lin * (this.level - 1);
      base[k] = base[k] + logPart + linPart;
    }

    /* 境界碾压系数 = multiplier^(realmNumber-1) */
    const realmNo = RealmReader.getRealmNumber(this.realmType);
    const bigMul = Math.pow(this.realmMultiplier, realmNo - 1);
    const smallMul = 1 + this.smallMulPerLayer * (this.realmSmall - 1);

    for (const k of Object.keys(base) as AttributeType[]) {
      base[k] *= bigMul * smallMul;
    }

    this.currentBaseAttributes = base;
  }

  /**
   * 验证属性值的有效性
   * @param attributes 待验证的属性对象
   * @throws 当属性值无效时抛出错误
   */
  private validateAttributes(attributes: Partial<Attribute>): void {
    Object.entries(attributes).forEach(([key, value]) => {
      if (value < 0) {
        throw new Error(`属性 ${key} 不能为负数: ${value}`);
      }
      if (!Number.isFinite(value)) {
        throw new Error(`属性 ${key} 必须是有效数字: ${value}`);
      }
    });
  }

  private attrAtLevel(
    n: number,
    base: number,
    grow: number,
    fade: number
  ): number {
    if (n <= 1) return base;
    const logPart = Math.log1p(n - 1);
    const fadePart = Math.pow(logPart, fade);
    return base + grow * fadePart;
  }
}
